package dao

import (
	"errors"
	"fmt"
	__ "shop-microservices/basic/goods_proto"
	"shop-microservices/basic/inits"
	"shop-microservices/handler/models"
	"strconv"
	"strings"
)

// 主键id查询商品并联店铺名称及属性
func GetGoodsById(id int64) (models.SelectSearchRes, error) {
	var g models.Goods
	g.Id = uint32(id)
	res, err := g.GetGoodsByIdWithShop()
	if err != nil {
		return models.SelectSearchRes{}, err
	}

	return res, nil
}

// 用户id与商品id查询 mysql 购物车数据并修改数量及价格
func GetByUserIdAndGoodsIdWithUpdatePriceAndNum(userId, goodsId, num int64, price float64) error {
	sh := models.ShopCars{
		UserId:     uint32(userId),
		GoodsId:    uint32(goodsId),
		PriceTotal: price,
		Num:        uint32(num),
	}
	if err := sh.UpdateShopCar(); err != nil {
		return errors.New("mysql修改购物车失败" + err.Error())
	}
	return nil
}

// 增加购物车商品数量
func AddShopCarNum(in *__.AddShopCarNumReq) error {
	// 获取商品数量
	num, err := GetShopCarData(in.UserId, in.GoodsId, "num")
	if err != nil {
		return err
	}
	// 查询商品
	g, err := GetGoodsById(in.GoodsId)
	if err != nil {
		return err
	}
	// 转换类型
	intNum, _ := strconv.Atoi(num)
	if g.GoodsStock <= uint32(intNum) {
		return errors.New("库存不足")
	}
	// 修改购买数量
	err = UpdateShopCarData(in.UserId, in.GoodsId, intNum+1, "num")
	if err != nil {
		return err
	}
	// 获取新价格
	newPrice := g.GoodsPrice * float64(intNum+1)
	// 更新 redis数据
	err = UpdateShopCarData(in.UserId, in.GoodsId, newPrice, "price")
	if err != nil {
		return err
	}
	// 修改mysql 数据
	err = GetByUserIdAndGoodsIdWithUpdatePriceAndNum(in.UserId, in.GoodsId, int64(intNum+1), newPrice)
	if err != nil {
		return err
	}
	return err
}

// 扣减购物车商品数量
func PopShopCarNum(in *__.PopShopCarNumReq) error {
	// 获取商品数量
	num, err := GetShopCarData(in.UserId, in.GoodsId, "num")
	if err != nil {
		return err
	}
	// 查询商品
	g, err := GetGoodsById(in.GoodsId)
	if err != nil {
		return err
	}
	intNum, _ := strconv.Atoi(num)
	// 扣至为0则删除
	if intNum-1 < 1 {
		// 扣减后数量为0则删除
		err = DelShopCarData(in.UserId, in.GoodsId)
		if err != nil {
			return err
		}
		err = DelByUserIdAndGoodsIdInMysql(in.UserId, in.GoodsId)
		if err != nil {
			return errors.New("删除购物车失败" + err.Error())
		}

	} else {
		err = UpdateShopCarData(in.UserId, in.GoodsId, intNum-1, "num")
		if err != nil {
			return err
		}

		newPrice := g.GoodsPrice * float64(intNum-1)
		err = UpdateShopCarData(in.UserId, in.GoodsId, newPrice, "price")
		if err != nil {
			return err
		}
		// 修改mysql购物车
		err = GetByUserIdAndGoodsIdWithUpdatePriceAndNum(in.UserId, in.GoodsId, int64(intNum-1), newPrice)
		if err != nil {
			return errors.New("mysql修改购物车失败" + err.Error())
		}
	}
	return err
}

// mysql 购物车删除对应数据
func DelByUserIdAndGoodsIdInMysql(userId, goodsId int64) error {
	sh := models.ShopCars{
		UserId:  uint32(userId),
		GoodsId: uint32(goodsId),
	}
	if err := sh.DeleteShopCar(); err != nil {
		return errors.New("删除mysql 购物车数据失败" + err.Error())
	}

	return nil
}

/*
SetInShoCar  存入购物车，已存在则添加对应数量
作用 -
	   获取商品目前状态
	   查询redis 中是否存在该商品的数据、
	   不存在则直接保存与redis 与 mysql
	   已存在则在原有数量上添加此次数据的数量
*/

func SetInShoCar(in *__.AddShopCarReq) error {
	g, err := GetGoodsById(in.GoodsId)
	if err != nil {
		return err
	}
	fmt.Println(g)
	if g.GoodsStatus != 1 {
		return errors.New("商品已下架")
	}
	if g.GoodsStock < uint32(in.Num) {
		return errors.New("商品库存不足")
	}

	key := fmt.Sprintf("shopCar:%d:%d", in.UserId, in.GoodsId)
	// 验证购物车是否存在
	res := GetShoCarExist(in.UserId, in.GoodsId)
	if !res {
		goodMap := map[string]interface{}{
			"id":        in.GoodsId,
			"goodsName": g.GoodsName,
			"num":       in.Num,
			"shopName":  g.ShopName,
			"goodsUrl":  g.GoodsUrl,
			"price":     float64(in.Num) * g.GoodsPrice,
			"brandName": g.BrandName,
			"goodsDesc": g.GoodsDesc,
			"color":     g.Color,
			"size":      g.Size,
			"material":  g.Material,
		}
		// 存入 redis 购物车
		err = inits.InitRedis(3).HMSet(inits.Ctx, key, goodMap).Err()
		if err != nil {
			return errors.New("加入购物车失败" + err.Error())
		}
		// 存入数据库
		sh := models.ShopCars{
			UserId:     uint32(in.UserId),
			GoodsId:    uint32(in.GoodsId),
			PriceTotal: float64(in.Num) * g.GoodsPrice,
			Num:        uint32(in.Num),
		}
		if err = sh.Create(); err != nil {
			return errors.New("mysql加入购物车失败" + err.Error())
		}
		// redis 已存在该商品
	} else {

		num, err1 := GetShopCarData(in.UserId, in.GoodsId, "num")
		if err1 != nil {
			return err1
		}
		fmt.Println()
		// 修改数量
		intNum, _ := strconv.Atoi(num)
		err1 = UpdateShopCarData(in.UserId, in.GoodsId, intNum+int(in.Num), "num")
		if err1 != nil {
			return err1
		}
		// 修改价格
		newPrice := g.GoodsPrice * float64(in.Num+int64(intNum))
		err1 = UpdateShopCarData(in.UserId, in.GoodsId, newPrice, "price")
		if err1 != nil {
			return err1
		}

		err = GetByUserIdAndGoodsIdWithUpdatePriceAndNum(in.UserId, in.GoodsId, in.Num, newPrice)
		if err != nil {
			return err
		}
		return err
	}
	return err
}

// 清空购物车
func CleanShopCar(userId int64) error {
	key := fmt.Sprintf("shopCar:%d:*", userId)
	keys := inits.InitRedis(3).Keys(inits.Ctx, key).Val()
	var err error
	for _, k := range keys {
		err = inits.InitRedis(3).Del(inits.Ctx, k).Err()

		if err != nil {
			res := fmt.Sprintf("键名为 %v 的数据删除失败:%v", k, err)
			return errors.New(res)
		}
	}

	var s models.ShopCars
	s.UserId = uint32(userId)
	err = s.DeleteShopCarByUserId()
	if err != nil {
		return errors.New("mysql 购物车数据删除失败")
	}
	return err
}

// 查找购物车数据对应字段
func GetShopCarData(userId, goodsId int64, field string) (string, error) {
	key := fmt.Sprintf("shopCar:%d:%d", userId, goodsId)
	data, err := inits.InitRedis(3).HGet(inits.Ctx, key, field).Result()
	if err != nil {
		return "", errors.New("查询失败" + err.Error())
	}
	if data == "" {
		return "", errors.New("不存在该数据")
	}

	return data, err
}

// 修改购物车某项数据
func UpdateShopCarData(userId, goodsId, num any, field string) error {
	key := fmt.Sprintf("shopCar:%d:%d", userId, goodsId)
	result := inits.InitRedis(3).HSet(inits.Ctx, key, field, num).Err()
	if result != nil {
		return errors.New("修改失败" + result.Error())
	}
	return nil
}

// 删除对应数据
func DelShopCarData(userId, goodsId int64) error {
	key := fmt.Sprintf("shopCar:%d:%d", userId, goodsId)
	err := inits.InitRedis(3).Del(inits.Ctx, key).Err()
	if err != nil {
		return errors.New("redis删除失败")
	}
	return nil
}

// 获取购物车商品总价
func GetShopCarTotalPrice(userId int64) float64 {
	key := fmt.Sprintf("shopCar:%d:*", userId)
	keys := inits.Rdb.Keys(inits.Ctx, key).Val()
	var priceTotal float64
	for _, v := range keys {
		goods := inits.InitRedis(3).HGetAll(inits.Ctx, v).Val()
		price, _ := strconv.ParseFloat(goods["price"], 64)
		priceTotal += price
	}
	return priceTotal
}

// 购物车商品列表
func GetShopCarList(userId int64) (shopCarList []*__.ShopCarList, err error) {
	key := fmt.Sprintf("shopCar:%d:*", userId)
	keys := inits.InitRedis(3).Keys(inits.Ctx, key).Val()

	for _, v := range keys {
		goods := inits.InitRedis(3).HGetAll(inits.Ctx, v).Val()
		goodsId, _ := strconv.Atoi(goods["id"])
		var g models.Goods
		g.Id = uint32(goodsId)
		err = g.GoodsDetail()
		if err != nil {
			return nil, errors.New("获取失败")
		}
		// 商品下架则删除商品
		if g.GoodsStatus == 2 {
			k := fmt.Sprintf("shopCar:%d:%d", userId, goodsId)
			inits.InitRedis(3).Del(inits.Ctx, k)
			continue
		}
		price, _ := strconv.ParseFloat(goods["price"], 64)
		// 商品库存不足购买数量自动改为库存值
		num, _ := strconv.Atoi(goods["num"])
		if g.GoodsStock < uint32(num) {
			num = int(g.GoodsStock)
			price = g.GoodsPrice * float64(num)
		}
		shopCarList = append(shopCarList, &__.ShopCarList{
			GoodsName:  goods["goodsName"],
			GoodsPrice: float32(price),
			GrandName:  goods["brandName"],
			GoodsUrl:   goods["goodsUrl"],
			GoodsDesc:  goods["goodsDesc"],
			ShopName:   goods["shopName"],
			Num:        int64(num),
			Id:         int64(goodsId),
			Color:      goods["color"],
			Material:   goods["material"],
			Size:       goods["size"],
		})
	}
	return
}

// 根据商品名查redis
func UserSearchShopCarByName(in *__.UserSearchShopCarByNameReq) (shopCarList []*__.ShopCarList, err error) {
	key := fmt.Sprintf("shopCar:%d:*", in.UserId)
	keys := inits.InitRedis(3).Keys(inits.Ctx, key).Val()

	for _, v := range keys {
		goods := inits.InitRedis(3).HGetAll(inits.Ctx, v).Val()
		res := strings.Contains(goods["goodsName"], in.Name)
		if !res {
			continue
		}

		goodsId, _ := strconv.Atoi(goods["id"])
		var g models.Goods
		g.Id = uint32(goodsId)
		err = g.GoodsDetail()
		if err != nil {
			return nil, errors.New("获取失败")
		}
		// 商品下架则删除商品
		if g.GoodsStatus == 2 {
			k := fmt.Sprintf("shopCar:%d:%d", in.UserId, goodsId)
			inits.InitRedis(3).Del(inits.Ctx, k)
			continue
		}
		// 商品库存不足购买数量自动改为库存值
		num, _ := strconv.Atoi(goods["num"])
		if g.GoodsStock < uint32(num) {
			num = int(g.GoodsStock)
		}
		price := g.GoodsPrice * float64(num)

		shopCarList = append(shopCarList, &__.ShopCarList{
			GoodsName:  goods["goodsName"],
			GoodsPrice: float32(price),
			GrandName:  goods["brandName"],
			GoodsUrl:   goods["goodsUrl"],
			GoodsDesc:  goods["goodsDesc"],
			ShopName:   goods["shopName"],
			Num:        int64(num),
			Id:         int64(goodsId),
			Color:      goods["color"],
			Material:   goods["material"],
			Size:       goods["size"],
		})
	}
	return
}

// 验证购物车中商品存在
func GetShoCarExist(userId, goodsId int64) bool {
	key := fmt.Sprintf("shopCar:%d:%d", userId, goodsId)
	res := inits.InitRedis(3).Exists(inits.Ctx, key).Val()
	if res != 1 {
		return false
	}
	return true
}
